package client;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public abstract class CommandInterpreter {

    private Map<String, CommandHandler> commands = new HashMap<>();

    public CommandInterpreter(CommandHandler defaultHandler) {
        this.defaultHandler = defaultHandler;
    }

    private CommandHandler defaultHandler;
    private boolean stop = true;

    public void addCommand(String command, CommandHandler handler) {
        if (command == null)
            throw new IllegalArgumentException("Command is null");
        if (handler == null)
            throw new IllegalArgumentException("Handler is null");
        commands.put(command, handler);
    }

    public void execCommand(String commandWithArgs) throws CommandExecException {
        if (commandWithArgs == null)
            throw new IllegalArgumentException("Command is null");

        String[] slice = commandWithArgs.split(" ", 2);
        String command = slice[0];
        String arguments = slice.length > 1 ? slice[1] : "";

        CommandHandler ch = commands.get(command);
        ch = ch != null ? ch : defaultHandler;

        try {
            ch.doCommand(commandWithArgs);
        } catch (Exception e) {
            throw new CommandExecException(commandWithArgs, e);
        }
    }

    public void start() {
        if (!stop)
            throw new IllegalStateException("Command interpreter already works!");
        stop = false;

        while (!stop) {
            try {
                String cmd = getCommandWithArgs();
                execCommand(cmd);
            } catch (CommandExecException e) {
                onCommandFail(e);
            } catch (Exception e) {
                onInternalError(e);
            }
        }
    }

    public void stop() {
        stop = true;
    }

    public abstract String getCommandWithArgs() throws IOException;

    public void onCommandFail(CommandExecException e) {
        System.out.println("Can't complete you command due: " + e.getReason());
    }

    public void onInternalError(Exception e) {

        System.out.println("Internal error: " + e);
    }
}
